home *** CD-ROM | disk | FTP | other *** search
- //////////
- //
- // File: QTReadWriteJPEG.c
- //
- // Contains: Sample code for compressing and decompressing JPEG images.
- //
- // Written by: Michael Marinkovich and Guillermo Ortiz
- // Revised by: Tim Monroe
- // Based heavily on the existing "JPEG Sample" code.
- //
- // Copyright: © 1996-1998 by Apple Computer, Inc., all rights reserved.
- //
- // Change History (most recent first):
- //
- // <4> 02/03/99 rtm reworked prompt and filename handling to remove "\p" sequences
- // <3> 04/27/98 rtm revised to uncouple this file from its Macintosh framework,
- // to make the coding style conform to other code samples, and
- // to make it run on Windows
- // <2> 02/??/97 mwm fixed some memory leaks; expanded JPEG parsing
- // <1> 04/03/96 mwm initial coding
- //
- // This sample code illustrates how to compress and decompress JPEG images using QuickTime.
- // We use the FCompressImage function, but you could also use the CompressImage function.
- // Although this sample demonstrates only JPEG compression/decompression, you could use this
- // as a framework for other types of compression (except for the decoding of the JPEG header).
- //
- // In this sample code, we allow the user to open a JPEG image file; then we draw it into
- // a window on the screen. Your application, of course, will probably want to do more
- // interesting things with the image. We also allow the user to save an image using JPEG
- // compression.
- //
- // NOTES:
- //
- // *** (1) ***
- // You may incorporate this sample code into your applications without restriction, though
- // the sample code has been provided "AS IS" and the responsibility for its operation is 100% yours.
- // However, what you are not permitted to do is to redistribute the source as "DSC Sample Code"
- // after having made changes. If you're going to redistribute the source, we require that you
- // make it clear in the source that the code was descended from Apple Sample Code, but that
- // you've made changes.
- //
- //////////
-
- //////////
- //
- // header files
- //
- //////////
-
- #include "QTReadWriteJPEG.h"
- #include "QTUtilities.h"
-
-
- //////////
- //
- // global variables
- //
- //////////
-
- GWorldPtr gGWorld = NULL; // the GWorld we load the image data into
- WindowPtr gImageWindow = NULL; // the window we display the image in
-
-
- //////////
- //
- // QTJPEG_PromptUserForJPEGFileAndDisplay
- // Let the user select a JPEG image file, then display it in a window.
- //
- //////////
-
- void QTJPEG_PromptUserForJPEGFileAndDisplay (void)
- {
- SFTypeList myTypeList;
- StandardFileReply myReply;
- PixMapHandle myPixMap;
- Rect myRect;
- OSErr myErr = noErr;
-
- // have the user select a JPEG image file
- myTypeList[0] = kQTFileTypeJPEG;
-
- StandardGetFilePreview(NULL, 1, myTypeList, &myReply);
- if (!myReply.sfGood)
- goto bail;
-
- // read the file data into an offscreen graphics world
- myErr = QTJPEG_ReadJPEG(myReply.sfFile, &gGWorld);
- if (myErr != noErr)
- goto bail;
-
- myRect = gGWorld->portRect;
- myPixMap = GetGWorldPixMap(gGWorld);
- if (LockPixels(myPixMap)) {
-
- // create a window to display the image in; then draw into that window
- MacOffsetRect(&myRect, 50, 50);
- gImageWindow = NewCWindow(NULL, &myRect, myReply.sfFile.name, true, movableDBoxProc, (WindowPtr)-1L, true, 0);
- if (gImageWindow == NULL)
- goto bail;
-
- MacOffsetRect(&myRect, -50, -50);
-
- // copy the image from the offscreen port into the window
- CopyBits( (BitMapPtr)(*myPixMap),
- (BitMapPtr)(&(gImageWindow->portBits)),
- &myRect,
- &gImageWindow->portRect,
- srcCopy,
- NULL);
- }
-
- bail:
- UnlockPixels(myPixMap);
- }
-
-
- //////////
- //
- // QTJPEG_ReadJPEG
- // Open a JPEG file with supplied FSSpec; the graphics world containing the image is returned through theGWorld.
- //
- //////////
-
- OSErr QTJPEG_ReadJPEG (FSSpec theFile, CGrafPtr *theGWorld)
- {
- ImageDescriptionHandle myDesc;
- Handle myData;
- GWorldPtr myGWorld = NULL;
- GWorldPtr oldWorld;
- GDHandle oldGD;
- PixMapHandle myPixMap;
- ICMDataProcRecord myLoadProc;
- Rect myRect;
- DLDataRec myDataRec;
- long mySize;
- short myRefNum;
- Ptr myDataPtr;
- OSErr myErr = paramErr;
-
- // save the current graphics port
- GetGWorld(&oldWorld, &oldGD);
-
- if (theGWorld != NULL) {
-
- myErr = FSpOpenDF(&theFile, fsRdWrShPerm, &myRefNum);
- if (myErr == noErr) {
-
- myDesc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
- if (myDesc != NULL) {
- HLock((Handle)myDesc);
- myErr = QTJPEG_ReadJPEGHeader(myRefNum, myDesc, &myRect);
- if (myErr == noErr) {
-
- myData = NewHandleClear(kBufferSize);
- myErr = MemError();
-
- if ((myData != NULL) && (myErr == noErr)) {
- myErr = QTJPEG_NewJPEGWorld(&myGWorld, (*myDesc)->depth, myRect);
- if ((myGWorld != NULL) && (myErr == noErr)){
- myErr = SetFPos(myRefNum, fsFromStart, 0);
- if (myErr == noErr) {
-
- myPixMap = GetGWorldPixMap(myGWorld);
- LockPixels(myPixMap);
- SetGWorld(myGWorld, NULL);
- HLock(myData);
-
- mySize = kBufferSize;
-
- // make sure the file size is greater than the buffer size
- (void)GetEOF(myRefNum, &mySize);
- if (kBufferSize > mySize)
- mySize = mySize;
-
- myErr = FSRead(myRefNum, &mySize, *myData);
- if (myErr == noErr) {
- mySize = (*myDesc)->dataSize - kBufferSize;
- if (mySize < 0)
- mySize = 0;
-
- myDataRec.fRefNum = myRefNum;
- myDataRec.fFileLength = mySize;
- myDataRec.fOrigPtr = *myData;
- myDataRec.fEndPtr = *myData + kBufferSize;
- myLoadProc.dataProc = NewICMDataProc(QTJPEG_DataLoadingProc);
- myLoadProc.dataRefCon = (long)&myDataRec;
-
- myDataPtr = StripAddress(*myData);
-
- myErr = FDecompressImage( myDataPtr,
- myDesc,
- myPixMap,
- &myRect,
- NULL,
- srcCopy,
- NULL,
- NULL,
- NULL,
- codecHighQuality,
- anyCodec,
- kBufferSize,
- &myLoadProc,
- NULL);
-
- DisposeRoutineDescriptor(myLoadProc.dataProc);
- HUnlock(myData);
- UnlockPixels(myPixMap);
-
- // restore the previous graphics world
- SetGWorld(oldWorld, oldGD);
-
- if (myErr == noErr)
- *theGWorld = myGWorld;
- }
- }
-
- if (myErr != noErr)
- DisposeGWorld(myGWorld);
- }
-
- DisposeHandle(myData);
- }
- }
-
- HUnlock((Handle)myDesc);
- DisposeHandle((Handle)myDesc);
- }
-
- FSClose(myRefNum); // close the file
- }
- }
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_ReadJPEGHeader
- // Read the JPEG header and fill out the specified ImageDescription with needed info.
- //
- //////////
-
- OSErr QTJPEG_ReadJPEGHeader (short theRefNum, ImageDescriptionHandle theDesc, Rect *theRect)
- {
- long mySize;
- short mySkip;
- UInt8 myMarker;
- Boolean isJFIF = false;
- Boolean readingExtension = false;
- OSErr myErr = noErr;
-
- // set file position to beginning of file
- myErr = SetFPos(theRefNum, fsFromStart , 0);
- if (myErr != noErr)
- return(myErr);
-
- // get file length, so we don't overflow
- myErr = GetEOF(theRefNum, &mySize);
- if (myErr != noErr)
- return(myErr);
-
- (*theDesc)->dataSize = mySize;
-
- // loop forever
- while (true) {
- myMarker = QTJPEG_FindNextMarker(theRefNum);
-
- switch (myMarker) {
- case kSOIMarker:
- isJFIF = true;
- break;
-
- case kAPPOMarker + 0:
- case kAPPOMarker + 1:
- case kAPPOMarker + 2:
- case kAPPOMarker + 3:
- case kAPPOMarker + 4:
- case kAPPOMarker + 5:
- case kAPPOMarker + 6:
- case kAPPOMarker + 7:
- case kAPPOMarker + 8:
- case kAPPOMarker + 9:
- case kAPPOMarker + 10:
- case kAPPOMarker + 11:
- case kAPPOMarker + 12:
- case kAPPOMarker + 13:
- case kAPPOMarker + 14:
- case kAPPOMarker + 15:
- myErr = QTJPEG_HandleAPPOMarker(myMarker, theRefNum, theDesc, &readingExtension);
- if (myErr != noErr)
- return(myErr);
- break;
-
- case kCommentMarker:
- QTJPEG_SkipLength(theRefNum);
- break;
-
- case kSOFMarker + 0: // start of frame header marker
- case kSOFMarker + 1:
- case kSOFMarker + 2:
- case kSOFMarker + 3:
- case kSOFMarker + 5:
- case kSOFMarker + 6:
- case kSOFMarker + 7:
- case kSOFMarker + 9:
- case kSOFMarker + 10:
- case kSOFMarker + 11:
- case kSOFMarker + 13:
- case kSOFMarker + 14:
- case kSOFMarker + 15:
- myErr = QTJPEG_HandleSOFMarker(theRefNum, theDesc, readingExtension);
- if (myErr != noErr)
- return(myErr);
-
- if (!readingExtension) {
- MacSetRect(theRect, 0, 0, (*theDesc)->width, (*theDesc)->height);
- return(noErr);
- }
- break;
-
- case kDACMarker:
- mySkip = QTJPEG_ReadWord(theRefNum) - 2;
- mySkip *= QTJPEG_ReadWord(theRefNum);
- myErr = SetFPos(theRefNum, fsFromMark, mySkip);
- break;
-
- case kSOSMarker:
- QTJPEG_HandleSOSMarker(theRefNum);
- break;
-
- case kDHTMarker:
- case kDQTMarker:
- case kRSTOMarker:
- QTJPEG_SkipLength(theRefNum);
- break;
-
- case kEOIMarker: // we reached the end of image
- // we are reading an extension so keep going
- if (readingExtension)
- readingExtension = false;
- break;
- }
- }
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_FindNextMarker
- // Find the next marker in the specified file.
- //
- //////////
-
- UInt8 QTJPEG_FindNextMarker (long theRefNum)
- {
- UInt8 myMarker;
-
- myMarker = QTJPEG_ReadByte(theRefNum);
-
- while (myMarker == kStartMarker)
- myMarker = QTJPEG_ReadByte(theRefNum);
-
- while (myMarker == 0x00) {
- myMarker = QTJPEG_ReadByte(theRefNum);
-
- while (myMarker != kStartMarker)
- myMarker = QTJPEG_ReadByte(theRefNum);
-
- myMarker = QTJPEG_ReadByte(theRefNum);
- }
-
- return(myMarker);
- }
-
-
- //////////
- //
- // QTJPEG_HandleAPPOMarker
- // Handle an APPO marker in the specified file.
- //
- //////////
-
- OSErr QTJPEG_HandleAPPOMarker (UInt8 theMarker, long theRefNum, ImageDescriptionHandle theDesc, Boolean *readingExtension)
- {
- Fixed xRes, yRes;
- long myLength;
- short myUnits;
- short myVersion;
- UInt8 myExtension;
- UInt8 myType[5];
- OSErr myErr = noErr;
-
- // read skip bytes - header length - skip count
- myLength = QTJPEG_ReadWord(theRefNum) - 2;
-
- if ((theMarker == kAPPOMarker) && (myLength >= 14)) {
- myType[0] = QTJPEG_ReadByte(theRefNum);
- myType[1] = QTJPEG_ReadByte(theRefNum);
- myType[2] = QTJPEG_ReadByte(theRefNum);
- myType[3] = QTJPEG_ReadByte(theRefNum);
- myType[4] = QTJPEG_ReadByte(theRefNum);
-
- // check to see if we really have the JFIF header
- if ((myType[0] == 'J') &&
- (myType[1] == 'F') &&
- (myType[2] == 'I') &&
- (myType[3] == 'F')) {
-
- myVersion = QTJPEG_ReadWord(theRefNum);
-
- if (myVersion < 0x100)
- return(paramErr); // don't know this
- else
- (*theDesc)->version = myVersion;
-
- myUnits = QTJPEG_ReadByte(theRefNum);
- xRes = QTJPEG_ReadWord(theRefNum);
- yRes = QTJPEG_ReadWord(theRefNum);
-
- switch (myUnits) {
- case 0: // no res, just aspect ratio
- xRes = FixMul(72L << 16, xRes << 16);
- yRes = FixMul(72L << 16, yRes << 16);
- break;
-
- case 1: // dots per inch
- xRes = xRes << 16;
- yRes = yRes << 16;
- break;
-
- case 2: // dots per centimeter (we convert to dpi )
- xRes = FixMul(0x28a3d, xRes << 16);
- yRes = FixMul(0x28a3d, xRes << 16); // yRes?? RTM
- break;
-
- default:
- break;
- }
-
- (*theDesc)->hRes = xRes;
- (*theDesc)->vRes = yRes;
-
- myLength -= 12;
- myErr = SetFPos(theRefNum, fsFromMark, myLength);
-
- } else {
- if ((myType[0] == 'J') &&
- (myType[1] == 'F') &&
- (myType[2] == 'X') &&
- (myType[3] == 'X')) {
-
- *readingExtension = true; // next markers are extensions; ignore them
-
- myExtension = QTJPEG_ReadByte(theRefNum);
- switch (myExtension) {
- case 0x10:
- case 0x11:
- case 0x13:
- break;
- default:
- return(paramErr);
- }
- }
- }
- } else
- myErr = SetFPos(theRefNum, fsFromMark, myLength);
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_HandleSOFMarker
- // Handle an SOF marker in the specified file.
- //
- //////////
-
- OSErr QTJPEG_HandleSOFMarker (long theRefNum, ImageDescriptionHandle theDesc, Boolean readingExtension)
- {
- short myWidth = 0;
- short myHeight = 0;
- short myComponents;
- short myLength;
- StringPtr myTitle = QTUtils_ConvertCToPascalString(kWindowTitle);
- OSErr myErr = noErr;
-
- if (!readingExtension) {
- myLength = QTJPEG_ReadWord(theRefNum);
- QTJPEG_ReadByte(theRefNum);
- myHeight = QTJPEG_ReadWord(theRefNum);
- myWidth = QTJPEG_ReadWord(theRefNum);
-
- // make sure we do have something to display
- if ((myWidth != 0) && (myHeight != 0)) {
-
- // now set up the image description
- (*theDesc)->idSize = sizeof(ImageDescription);
- (*theDesc)->cType = FOUR_CHAR_CODE('jpeg');
- (*theDesc)->dataRefIndex = 0;
- (*theDesc)->revisionLevel = 0;
- (*theDesc)->vendor = 0;
- (*theDesc)->temporalQuality = 0;
- (*theDesc)->spatialQuality = codecNormalQuality;
- (*theDesc)->width = myWidth;
- (*theDesc)->height = myHeight;
- (*theDesc)->frameCount = 1;
- BlockMove(myTitle, (*theDesc)->name, 13);
- (*theDesc)->clutID = -1;
-
- myComponents = QTJPEG_ReadByte(theRefNum);
-
- switch (myComponents) {
- case 1:
- (*theDesc)->depth = 40;
- break;
-
- case 3:
- (*theDesc)->depth = 32;
- break;
-
- case 4:
- (*theDesc)->depth = 32;
- break;
-
- default:
- myErr = paramErr;
- return(myErr);
- break;
- }
-
- myErr = SetFPos(theRefNum, fsFromMark, myLength - 8);
- return(noErr);
- }
-
- } else {
- myLength = QTJPEG_ReadWord(theRefNum) - 2;
- myErr = SetFPos(theRefNum, fsFromMark, myLength);
- if (myErr != noErr)
- return(myErr);
- }
-
- free(myTitle);
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_HandleSOSMarker
- // Handle an SOS marker in the specified file.
- //
- //////////
-
- void QTJPEG_HandleSOSMarker (long theRefNum)
- {
- short myComponents;
- short myWord;
-
- QTJPEG_ReadWord(theRefNum);
- myComponents = QTJPEG_ReadByte(theRefNum);
-
- for (myWord = 0; myWord < myComponents; myWord++)
- QTJPEG_ReadWord(theRefNum);
- }
-
-
- //////////
- //
- // QTJPEG_ReadByte
- // Read the next byte from the specified file.
- //
- //////////
-
- UInt8 QTJPEG_ReadByte (short theRefNum)
- {
- UInt8 myData;
- long myBytesNeeded = sizeof(char);
-
- (void)FSRead(theRefNum, &myBytesNeeded, &myData);
- return(myData);
- }
-
-
- //////////
- //
- // QTJPEG_ReadWord
- // Read the next word from the specified file.
- //
- //////////
-
- UInt16 QTJPEG_ReadWord (short theRefNum)
- {
- UInt16 myData;
- long myBytesNeeded = sizeof(UInt16);
-
- (void)FSRead(theRefNum, &myBytesNeeded, &myData);
-
- // in JPEG files, the data is stored in a big-endian order
- myData = EndianU16_BtoN(myData);
- return(myData);
- }
-
-
- //////////
- //
- // QTJPEG_SkipLength
- // Skip over the length word.
- //
- //////////
-
- void QTJPEG_SkipLength (long theRefNum)
- {
- UInt16 mySkip;
-
- mySkip = QTJPEG_ReadWord(theRefNum) - 2;
- SetFPos(theRefNum, fsFromMark, mySkip);
- }
-
-
- //////////
- //
- // QTJPEG_NewJPEGWorld
- // Return, through the theWorld parameter, a new offscreen graphics world suitable
- // for drawing a JPEG image of the specified bitdepth into.
- //
- //////////
-
- OSErr QTJPEG_NewJPEGWorld (GWorldPtr *theWorld, short theDepth, Rect theRect)
- {
- GWorldPtr oldPort;
- GDHandle oldGD;
- PixMapHandle myPixMap;
- CTabHandle myCTab = NULL;
- OSErr myErr = paramErr;
-
- if (theWorld != NULL) {
- // save the current graphics port
- GetGWorld(&oldPort, &oldGD);
-
- // if depth is greater than 32, then the image is grayscale
- if (theDepth > 32) {
- myCTab = GetCTable(theDepth);
- theDepth = theDepth - 32;
- }
-
- // first try to allocate a GWorld in the application's heap
- myErr = NewGWorld(theWorld, theDepth, &theRect, myCTab, NULL, 0L);
-
- // otherwise, try to allocate a GWorld in temporary memory
- if (myErr != noErr)
- myErr = NewGWorld(theWorld, theDepth, &theRect, myCTab, NULL, useTempMem);
-
- if ((myErr == noErr) && (theWorld != NULL)) {
- myPixMap = GetGWorldPixMap(*theWorld);
- if (LockPixels(myPixMap)) {
- SetGWorld(*theWorld, NULL);
- EraseRect(&theRect);
- UnlockPixels(myPixMap);
- }
- }
-
- SetGWorld(oldPort, oldGD);
- }
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_SaveJPEG
- // Save the specified image as a compressed file.
- //
- //////////
-
- OSErr QTJPEG_SaveJPEG (GWorldPtr theWorld)
- {
- StandardFileReply myReply;
- ImageDescriptionHandle myDesc;
- Handle myData;
- Rect myRect;
- PixMapHandle myPixMap;
- CTabHandle myCTab = NULL;
- ICMFlushProcRecord myFlushProc;
- short myRefNum;
- short myDepth;
- StringPtr myImagePrompt = QTUtils_ConvertCToPascalString(kSaveImagePrompt);
- StringPtr myImageFileName = QTUtils_ConvertCToPascalString(kSaveImageFileName);
- OSErr myErr = paramErr;
-
- if (theWorld == NULL)
- goto bail;
-
- // have the user select the name of the new image file
- StandardPutFile(myImagePrompt, myImageFileName, &myReply);
- if (!myReply.sfGood)
- goto bail;
-
- myDesc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription));
- if (myDesc == NULL)
- goto bail;
-
- myRect = theWorld->portRect;
- myPixMap = GetGWorldPixMap(theWorld);
-
- if (LockPixels(myPixMap)) {
-
- // if less than 16-bit then get the color table of our GWorld
- myDepth = (**myPixMap).pixelSize;
- if (myDepth < 16)
- myCTab = (**myPixMap).pmTable;
-
- myData = NewHandle(kBufferSize);
- myErr = MemError();
-
- if ((myData != NULL) && (myErr == noErr)) {
- CodecType myCodec = kJPEGCodecType;
-
- HLock(myData);
-
- if (myReply.sfReplacing)
- myErr = FSpDelete(&myReply.sfFile);
-
- myErr = FSpCreate(&myReply.sfFile, kImageFileCreator, kQTFileTypeJPEG, myReply.sfScript);
-
- if (myErr == noErr)
- myErr = FSpOpenDF(&myReply.sfFile, fsRdWrPerm, &myRefNum);
-
- if (myErr == noErr)
- myErr = SetFPos(myRefNum, fsFromStart, 0);
-
- if (myErr == noErr) {
- ICMFlushProcRecordPtr myFlushProcPtr = NULL;
-
- myFlushProc.flushProc = NewICMFlushProc(QTJPEG_DataUnloadProc);
- myFlushProc.flushRefCon = myRefNum;
- myFlushProcPtr = &myFlushProc;
-
- // compress the image
- myErr = FCompressImage( myPixMap,
- &myRect,
- myDepth,
- codecNormalQuality,
- myCodec,
- anyCodec,
- myCTab,
- codecFlagWasCompressed,
- kBufferSize,
- myFlushProcPtr,
- NULL,
- myDesc,
- *myData);
-
- if (myErr == noErr)
- myErr = SetFPos(myRefNum, fsFromStart, (**myDesc).dataSize);
-
- if (myErr == noErr)
- myErr = SetEOF(myRefNum, (**myDesc).dataSize);
-
- if (myErr == noErr)
- myErr = FSClose(myRefNum);
-
- HUnlock(myData);
- DisposeHandle(myData);
-
- DisposeRoutineDescriptor(myFlushProc.flushProc);
- }
- }
- }
-
- UnlockPixels(myPixMap);
-
- bail:
- if (myDesc != NULL)
- DisposeHandle((Handle)myDesc);
-
- free(myImagePrompt);
- free(myImageFileName);
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_DataUnloadProc
- // A data unloading procedure: write the compressed data to disk.
- //
- // The theRefCon parameter is assumed to be a file reference number of an open file.
- //
- //////////
-
- PASCAL_RTN OSErr QTJPEG_DataUnloadProc (Ptr theData, long theBytesNeeded, long theRefCon)
- {
- OSErr myErr = noErr;
-
- if (theData == NULL) {
- // if data is NULL, set a new position in the file from the current mark, offset by bytesNeeded
- myErr = SetFPos(theRefCon, fsFromMark, theBytesNeeded);
- } else {
- // otherwise, write the specified data to disk
- myErr = FSWrite(theRefCon, &theBytesNeeded, theData);
- }
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTJPEG_DataLoadingProc
- // A data loading procedure: read the data from disk.
- //
- // The theRefCon parameter is assumed to be a pointer to our custom data-loading record.
- //
- //////////
-
- PASCAL_RTN OSErr QTJPEG_DataLoadingProc (Ptr *theData, long theBytesNeeded, long theRefCon)
- {
- long myUnusedDataLen;
- long myNewDataLen;
- DLDataPtr myDataRec;
- Ptr myDataPtr;
- OSErr myErr = noErr;
-
- myDataRec = (DLDataPtr)theRefCon;
-
- if (theData == NULL) {
- myErr = SetFPos(myDataRec->fRefNum, fsFromMark, theBytesNeeded);
- } else {
- myDataPtr = *theData;
-
- // if QT requests more data than is in the buffer, we will have to load more
- if ((myDataPtr + theBytesNeeded) >= myDataRec->fEndPtr) {
- // move whats left up to the front of the buffer
- myUnusedDataLen = myDataRec->fEndPtr - myDataPtr;
- BlockMove(myDataPtr, myDataRec->fOrigPtr, myUnusedDataLen);
-
- // now fill the buffer with new data,
- // following the data we moved to the front of the buffer
- myNewDataLen = kBufferSize - myUnusedDataLen;
-
- if (myNewDataLen > myDataRec->fFileLength)
- myNewDataLen = myDataRec->fFileLength;
-
- myDataPtr = myDataRec->fOrigPtr + myUnusedDataLen;
-
- myErr = FSRead(myDataRec->fRefNum, &myNewDataLen, myDataPtr);
-
- myDataRec->fFileLength -= myNewDataLen;
-
- *theData = myDataRec->fOrigPtr;
- }
- }
-
- return(myErr);
- }
-